home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / net / ds3100.md / netLEXmit.c < prev   
C/C++ Source or Header  |  1991-02-12  |  18KB  |  637 lines

  1. /* 
  2.  * netLEXmit.c --
  3.  *
  4.  *    Routines to transmit packets on the LANCE interface.
  5.  *
  6.  * Copyright (C) 1989 Digital Equipment Corporation.
  7.  * Permission to use, copy, modify, and distribute this software and
  8.  * its documentation for any purpose and without fee is hereby granted,
  9.  * provided that the above copyright notice appears in all copies.  
  10.  * Digital Equipment Corporation makes no representations about the
  11.  * suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  */
  14.  
  15. #ifndef lint
  16. static char rcsid[] = "$Header: /sprite/src/kernel/net/ds3100.md/RCS/netLEXmit.c,v 9.4 91/02/12 14:15:23 jhh Exp $ SPRITE (DECWRL)";
  17. #endif not lint
  18.  
  19. #include <sprite.h>
  20. #include <netLEInt.h>
  21. #include <sys.h>
  22. #include <vm.h>
  23. #include <list.h>
  24. #include <sync.h>
  25. #include <machMon.h>
  26.  
  27.  
  28. /*
  29.  *----------------------------------------------------------------------
  30.  *
  31.  * OutputPacket --
  32.  *
  33.  *    Assemble and output the packet in the given scatter/gather element.
  34.  *    The ethernet header contains the address of the destination host
  35.  *    and the higher level protocol type already.
  36.  *
  37.  * Results:
  38.  *    FAILURE if something went wrong.
  39.  *
  40.  * Side effects:
  41.  *    Transmit command list is modified to contain the packet.
  42.  *
  43.  *----------------------------------------------------------------------
  44.  */
  45. static ReturnStatus
  46. OutputPacket(etherHdrPtr, scatterGatherPtr, scatterGatherLength, statePtr)
  47.     Net_EtherHdr        *etherHdrPtr;    /* Ethernet header of packet.*/
  48.     register Net_ScatterGather    *scatterGatherPtr; /* Data portion of packet.*/
  49.     int                scatterGatherLength;/* Length of data portion 
  50.                              * gather array. */
  51.     NetLEState        *statePtr;        /* The interface state. */
  52. {
  53.     register short        *inBufPtr;
  54.     register volatile short    *outBufPtr;
  55.     register Address        descPtr;
  56.     register int        length;
  57.     unsigned    char        *leftOverBytePtr = (unsigned char *)NIL;
  58.     int                totLen;
  59.     int                i;
  60.  
  61.     descPtr = statePtr->xmitDescFirstPtr;
  62.  
  63.     /*
  64.      * Do a sanity check.
  65.      */
  66.     if (*BUF_TO_ADDR(descPtr, NET_LE_XMIT_STATUS1) & NET_LE_XMIT_CHIP_OWNED) {
  67.     printf("LE ethernet: Transmit buffer owned by chip.\n");
  68.     return (FAILURE);
  69.     }
  70.  
  71.     statePtr->transmitting = TRUE;
  72.     statePtr->curScatGathPtr = scatterGatherPtr;
  73.     etherHdrPtr->source = statePtr->etherAddress;
  74.     outBufPtr = (volatile short *)statePtr->xmitBufPtr;
  75.  
  76.     /* 
  77.      * Copy the packet into the xmit buffer.  Don't be general, be fast.
  78.      * First do the ethernet header.
  79.      */
  80.     inBufPtr = (short *)etherHdrPtr;
  81.     *outBufPtr = *inBufPtr;
  82.     *(outBufPtr + 2) = *(inBufPtr + 1);
  83.     *(outBufPtr + 4) = *(inBufPtr + 2);
  84.     *(outBufPtr + 6) = *(inBufPtr + 3);
  85.     *(outBufPtr + 8) = *(inBufPtr + 4);
  86.     *(outBufPtr + 10) = *(inBufPtr + 5);
  87.     *(outBufPtr + 12) = *(inBufPtr + 6);
  88.     outBufPtr += 14;
  89.     totLen = sizeof(Net_EtherHdr);
  90.  
  91.     /*
  92.      * Now do each element of the scatter/gather array.
  93.      */
  94.     for (i = 0; i < scatterGatherLength; i++,scatterGatherPtr++ ) {
  95.     unsigned char *bufAddr;
  96.  
  97.     length = scatterGatherPtr->length;
  98.     if (length == 0) {
  99.         continue;
  100.     }
  101.     totLen += length;
  102.     if (totLen > NET_ETHER_MAX_BYTES) {
  103.         printf("OutputPacket: Packet too large\n");
  104.         statePtr->curScatGathPtr = (Net_ScatterGather *)NIL;
  105.         statePtr->transmitting = FALSE;
  106.         return(FAILURE);
  107.     }
  108.     bufAddr = (unsigned char *)scatterGatherPtr->bufAddr;
  109.     /*
  110.      * Copy the element into the buffer.
  111.      */
  112.     if (leftOverBytePtr != (unsigned char *)NIL) {
  113.         /*
  114.          * We had one byte left over in the last piece of the packet.
  115.          * Concatenate this byte with the first byte of this piece.
  116.          */
  117.         *outBufPtr = *leftOverBytePtr | (*bufAddr << 8);
  118.         leftOverBytePtr = (unsigned char *)NIL;
  119.         bufAddr++;
  120.         outBufPtr += 2;
  121.         length--;
  122.     }
  123.  
  124. #define COPY_OUT(n) \
  125.     *(outBufPtr + n) = *(bufAddr + n) | (*(bufAddr + n + 1) << 8)
  126.  
  127. #define COPY_OUT2(n) \
  128.     *(outBufPtr + n) = *(short *)(bufAddr + n)
  129.  
  130.     if ((unsigned)bufAddr & 1) {
  131.         while (length > 64) {
  132.         COPY_OUT(0);  COPY_OUT(2);  COPY_OUT(4);  COPY_OUT(6);
  133.         COPY_OUT(8);  COPY_OUT(10); COPY_OUT(12); COPY_OUT(14);
  134.         COPY_OUT(16); COPY_OUT(18); COPY_OUT(20); COPY_OUT(22);
  135.         COPY_OUT(24); COPY_OUT(26); COPY_OUT(28); COPY_OUT(30);
  136.         COPY_OUT(32); COPY_OUT(34); COPY_OUT(36); COPY_OUT(38);
  137.         COPY_OUT(40); COPY_OUT(42); COPY_OUT(44); COPY_OUT(46);
  138.         COPY_OUT(48); COPY_OUT(50); COPY_OUT(52); COPY_OUT(54);
  139.         COPY_OUT(56); COPY_OUT(58); COPY_OUT(60); COPY_OUT(62);
  140.         outBufPtr += 64;
  141.         bufAddr += 64;
  142.         length -= 64;
  143.         }
  144.  
  145.         while (length > 16) {
  146.         COPY_OUT(0);  COPY_OUT(2);  COPY_OUT(4);  COPY_OUT(6);
  147.         COPY_OUT(8);  COPY_OUT(10); COPY_OUT(12); COPY_OUT(14);
  148.         outBufPtr += 16;
  149.         bufAddr += 16;
  150.         length -= 16;
  151.         }
  152.         while (length > 1) {
  153.         *outBufPtr = *bufAddr | (*(bufAddr + 1) << 8);
  154.         outBufPtr += 2;
  155.         bufAddr += 2;
  156.         length -= 2;
  157.         }
  158.     } else {
  159.         while (length >= 64) {
  160.         COPY_OUT2(0);  COPY_OUT2(2);  COPY_OUT2(4);  COPY_OUT2(6);
  161.         COPY_OUT2(8);  COPY_OUT2(10); COPY_OUT2(12); COPY_OUT2(14);
  162.         COPY_OUT2(16); COPY_OUT2(18); COPY_OUT2(20); COPY_OUT2(22);
  163.         COPY_OUT2(24); COPY_OUT2(26); COPY_OUT2(28); COPY_OUT2(30);
  164.         COPY_OUT2(32); COPY_OUT2(34); COPY_OUT2(36); COPY_OUT2(38);
  165.         COPY_OUT2(40); COPY_OUT2(42); COPY_OUT2(44); COPY_OUT2(46);
  166.         COPY_OUT2(48); COPY_OUT2(50); COPY_OUT2(52); COPY_OUT2(54);
  167.         COPY_OUT2(56); COPY_OUT2(58); COPY_OUT2(60); COPY_OUT2(62);
  168.         outBufPtr += 64;
  169.         bufAddr += 64;
  170.         length -= 64;
  171.         }
  172.  
  173.         while (length >= 16) {
  174.         COPY_OUT2(0);  COPY_OUT2(2);  COPY_OUT2(4);  COPY_OUT2(6);
  175.         COPY_OUT2(8);  COPY_OUT2(10); COPY_OUT2(12); COPY_OUT2(14);
  176.         outBufPtr += 16;
  177.         bufAddr += 16;
  178.         length -= 16;
  179.         }
  180.         while (length > 1) {
  181.         *outBufPtr = *(short *)bufAddr;
  182.         outBufPtr += 2;
  183.         bufAddr += 2;
  184.         length -= 2;
  185.         }
  186.     }
  187.     if (length == 1) {
  188.         leftOverBytePtr = bufAddr;
  189.     }
  190.     }
  191.     if (leftOverBytePtr != (unsigned char *)NIL) {
  192.     *outBufPtr = *leftOverBytePtr;
  193.     }
  194.  
  195.     /*
  196.      * Add the buffer to the ring.
  197.      */
  198.     if (totLen < NET_ETHER_MIN_BYTES) {
  199.     totLen = NET_ETHER_MIN_BYTES;
  200.     }
  201.     if ((rpc_SanityCheck) && (etherHdrPtr->type == NET_ETHER_SPRITE)) {
  202.     ReturnStatus    status;
  203.     status = Rpc_SanityCheck(scatterGatherLength, scatterGatherPtr, totLen);
  204.     if (status != SUCCESS) {
  205.         netLEDebugState = *statePtr;
  206.         NetLEReset(statePtr->interPtr);
  207.         panic("Sanity check failed.\n");
  208.     }
  209.     }
  210.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_BUF_SIZE) = -totLen;
  211.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_BUF_ADDR_LOW) = 
  212.             BUF_TO_CHIP_ADDR(statePtr->xmitBufPtr) & 0xFFFF;
  213.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS1) =
  214.         ((BUF_TO_CHIP_ADDR(statePtr->xmitBufPtr) >> 16) & 
  215.             NET_LE_XMIT_BUF_ADDR_HIGH) |
  216.             NET_LE_XMIT_START_OF_PACKET | 
  217.             NET_LE_XMIT_END_OF_PACKET |
  218.             NET_LE_XMIT_CHIP_OWNED;
  219.  
  220.     /*
  221.      * Give the chip a little kick.
  222.      */
  223.     *statePtr->regAddrPortPtr = NET_LE_CSR0_ADDR;
  224.     *statePtr->regDataPortPtr =
  225.         (NET_LE_CSR0_XMIT_DEMAND | NET_LE_CSR0_INTR_ENABLE);
  226.     return (SUCCESS);
  227.  
  228. }
  229.  
  230.  
  231.  
  232. /*
  233.  *----------------------------------------------------------------------
  234.  *
  235.  * AllocateXmitMem --
  236.  *
  237.  *    Allocate kernel memory for transmission ring.    
  238.  *
  239.  * Results:
  240.  *    None.
  241.  *
  242.  * Side effects:
  243.  *    Device state structure is updated.
  244.  *
  245.  *----------------------------------------------------------------------
  246.  */
  247. static void
  248. AllocateXmitMem(statePtr)
  249.     NetLEState        *statePtr;     /* State of the interface. */
  250. {
  251.     /*
  252.      * Allocate a transmission buffer descriptor.  
  253.      * The descriptor must start on an 8-byte boundary.  
  254.      */
  255.     statePtr->xmitDescFirstPtr = NetLEMemAlloc(NET_LE_XMIT_DESC_SIZE, FALSE);
  256.  
  257.     /*
  258.      * Allocate a buffer for a transmitted packet.
  259.      */
  260.     statePtr->xmitBufPtr = NetLEMemAlloc(NET_ETHER_MAX_BYTES, TRUE);
  261.  
  262.     statePtr->xmitMemAllocated = TRUE;
  263. }
  264.  
  265.  
  266. /*
  267.  *----------------------------------------------------------------------
  268.  *
  269.  * NetLEXmitInit --
  270.  *
  271.  *    Initialize the transmission queue structures.  This includes setting
  272.  *    up the transmission ring buffers.
  273.  *
  274.  * Results:
  275.  *    None.
  276.  *
  277.  * Side effects:
  278.  *    The transmission ring is initialized.
  279.  *
  280.  *----------------------------------------------------------------------
  281.  */
  282. void
  283. NetLEXmitInit(statePtr)
  284.     NetLEState        *statePtr;     /* State of the interface. */
  285. {
  286.     Address    descPtr;
  287.  
  288.     if (!statePtr->xmitMemAllocated) {
  289.     AllocateXmitMem(statePtr);
  290.     }
  291.     statePtr->xmitMemInitialized = TRUE;
  292.  
  293.     /*
  294.      * Initialize the state structure to point to the ring. xmitDescFirstPtr
  295.      * is set by AllocateXmitMem() and never moved.
  296.      */
  297.     statePtr->xmitDescLastPtr = statePtr->xmitDescFirstPtr;
  298.     statePtr->xmitDescNextPtr = statePtr->xmitDescFirstPtr;
  299.  
  300.     descPtr = statePtr->xmitDescFirstPtr;
  301.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_BUF_ADDR_LOW) = 0;
  302.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS1) = 0;
  303.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS2) = 0;
  304.  
  305.     statePtr->transmitting = FALSE;
  306.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  307. }
  308.  
  309.  
  310. /*
  311.  *----------------------------------------------------------------------
  312.  *
  313.  * NetLEXmitDone --
  314.  *
  315.  *    This routine will process a completed transmit command.  It will
  316.  *    check for errors and update the transmission ring pointers.
  317.  *
  318.  * Results:
  319.  *    FAILURE if problem is found.
  320.  *
  321.  * Side effects:
  322.  *    None.
  323.  *
  324.  *----------------------------------------------------------------------
  325.  */
  326.  
  327. ReturnStatus
  328. NetLEXmitDone(statePtr)
  329.     NetLEState        *statePtr;     /* State of the interface. */
  330. {
  331.     register    NetXmitElement    *xmitElementPtr;
  332.     register    Address        descPtr;
  333.     ReturnStatus        status;
  334.     unsigned            status1;
  335.     unsigned            status2;
  336.  
  337.     descPtr = (Address)statePtr->xmitDescNextPtr;
  338.  
  339.     /*
  340.      * Reset the interrupt.
  341.      */
  342.     *statePtr->regAddrPortPtr = NET_LE_CSR0_ADDR;
  343.     *statePtr->regDataPortPtr = 
  344.         (NET_LE_CSR0_XMIT_INTR | NET_LE_CSR0_INTR_ENABLE);
  345.  
  346.     /*
  347.      * If there is nothing that is currently being sent then something is
  348.      * wrong.
  349.      */
  350.     if (statePtr->curScatGathPtr == (Net_ScatterGather *) NIL) {
  351.     printf( "NetLEXmitDone: No current packet\n.");
  352.     return (FAILURE);
  353.     }
  354.  
  355.     status1 = *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS1);
  356.     status2 = *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS2);
  357.     if (status1 & NET_LE_XMIT_CHIP_OWNED) {
  358.     printf("netLE: Bogus transmit interrupt. Buffer owned by chip.\n");
  359.     return (FAILURE);
  360.     }
  361.  
  362.     /*
  363.      * Check for errors.
  364.      */
  365.     if (status1 & NET_LE_XMIT_ERROR) {
  366.     statePtr->stats.xmitPacketsDropped++;
  367.     if (status2 & NET_LE_XMIT_LOST_CARRIER) {
  368.         printf("LE ethernet: Lost carrier.\n");
  369.     }
  370.     /*
  371.      * Loss of carrier seems to also causes late collision.
  372.      * Print only one of the messages.
  373.      */
  374.     if ((status2 & NET_LE_XMIT_LATE_COLLISION) && 
  375.         !(status2 & NET_LE_XMIT_LOST_CARRIER)) {
  376.         printf("LE ethernet: Transmit late collision.\n");
  377.     }
  378.     if (status2 & NET_LE_XMIT_RETRY_ERROR) {
  379.         statePtr->stats.xmitCollisionDrop++;
  380.         statePtr->stats.collisions += 16;
  381.         printf("LE ethernet: Too many collisions.\n");
  382.     }
  383.     if (status2 & NET_LE_XMIT_UNDER_FLOW_ERROR) {
  384.         printf("LE ethernet: Memory underflow error.\n");
  385.         return (FAILURE);
  386.     }
  387.     }
  388.     if (status2 & NET_LE_XMIT_BUFFER_ERROR) {
  389.     printf("LE ethernet: Transmit buffering error.\n");
  390.     return (FAILURE);
  391.     }
  392.     if (status1 & NET_LE_XMIT_ONE_RETRY) {
  393.     statePtr->stats.collisions++;
  394.     }
  395.     if (status1 & NET_LE_XMIT_RETRIES) {
  396.     /*
  397.      * Two is more than one.  
  398.      */
  399.     statePtr->stats.collisions += 2;    /* Only a guess. */
  400.     }
  401.  
  402.     statePtr->stats.packetsSent++;
  403.  
  404.     /*
  405.      * Mark the packet as done.
  406.      */
  407.     statePtr->curScatGathPtr->done = TRUE;
  408.     if (statePtr->curScatGathPtr->mutexPtr != (Sync_Semaphore *) NIL) {
  409.     NetOutputWakeup(statePtr->curScatGathPtr->mutexPtr);
  410.     }
  411.  
  412.     /*
  413.      * If there are more packets to send then send the first one on
  414.      * the queue.  Otherwise there is nothing being transmitted.
  415.      */
  416.     status = SUCCESS;
  417.     if (!List_IsEmpty(statePtr->xmitList)) {
  418.     xmitElementPtr = (NetXmitElement *) List_First(statePtr->xmitList);
  419.     status = OutputPacket(xmitElementPtr->etherHdrPtr,
  420.              xmitElementPtr->scatterGatherPtr,
  421.              xmitElementPtr->scatterGatherLength, statePtr);
  422.     List_Move((List_Links *) xmitElementPtr, 
  423.           LIST_ATREAR(statePtr->xmitFreeList));
  424.     } else {
  425.     statePtr->transmitting = FALSE;
  426.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  427.     }
  428.     return (status);
  429. }
  430.  
  431.  
  432. /*
  433.  *----------------------------------------------------------------------
  434.  *
  435.  * NetLEOutput --
  436.  *
  437.  *    Output a packet.  The procedure is to either put the packet onto the 
  438.  *    queue of outgoing packets if packets are already being sent, or 
  439.  *    otherwise to send the packet directly.  The elements of the scatter 
  440.  *    array which come into this routine must satisfy the following two 
  441.  *    properties:
  442.  *
  443.  *
  444.  * Results:
  445.  *    None.
  446.  *
  447.  * Side effects:
  448.  *    Queue of packets modified.
  449.  *
  450.  *----------------------------------------------------------------------
  451.  */
  452.  
  453. ReturnStatus
  454. NetLEOutput(interPtr, etherHdrPtr, scatterGatherPtr, scatterGatherLength, rpc,
  455.     statusPtr)
  456.     Net_Interface    *interPtr;    /* The network interface. */
  457.     Net_EtherHdr    *etherHdrPtr;    /* Ethernet header for the packet. */
  458.     register    Net_ScatterGather    *scatterGatherPtr; /* Data portion of 
  459.                                 * the packet. */
  460.     int            scatterGatherLength;    /* Length of data portion gather
  461.                          * array. */
  462.     Boolean        rpc;        /* Is this an rpc packet? */
  463.     ReturnStatus    *statusPtr;    /* Status from sending packet. */
  464. {
  465.     register    NetXmitElement        *xmitPtr;
  466.     ReturnStatus            status;
  467.     NetLEState                *statePtr;
  468.  
  469.     statePtr = (NetLEState *) interPtr->interfaceData;
  470.     DISABLE_INTR();
  471.  
  472.     statePtr->stats.packetsOutput++;
  473.  
  474.     /*
  475.      * See if the packet is for us.  In this case just copy in the packet
  476.      * and call the higher level routine.
  477.      */
  478.  
  479.     if (NET_ETHER_COMPARE(statePtr->etherAddress, etherHdrPtr->destination)) {
  480.     int i, length;
  481.  
  482.         length = sizeof(Net_EtherHdr);
  483.         for (i = 0; i < scatterGatherLength; i++) {
  484.             length += scatterGatherPtr[i].length;
  485.         }
  486.  
  487.         if (length <= NET_ETHER_MAX_BYTES) {
  488.         register Address bufPtr;
  489.  
  490.         etherHdrPtr->source = statePtr->etherAddress;
  491.  
  492.         bufPtr = (Address)statePtr->loopBackBuffer;
  493.         bcopy((Address)etherHdrPtr, bufPtr, sizeof(Net_EtherHdr));
  494.         bufPtr += sizeof(Net_EtherHdr);
  495.             Net_GatherCopy(scatterGatherPtr, scatterGatherLength, bufPtr);
  496.  
  497.         Net_Input(interPtr,(Address)statePtr->loopBackBuffer, length);
  498.         }
  499.  
  500.         scatterGatherPtr->done = TRUE;
  501.     if (statusPtr != (ReturnStatus *) NIL) {
  502.         *statusPtr = SUCCESS;
  503.     }
  504.  
  505.     ENABLE_INTR();
  506.     return SUCCESS;
  507.     }
  508.  
  509.     /*
  510.      * If no packet is being sent then go ahead and send this one.
  511.      */
  512.  
  513.     if (!statePtr->transmitting) {
  514.     status = 
  515.         OutputPacket(etherHdrPtr, scatterGatherPtr, scatterGatherLength,
  516.             statePtr);
  517.     if (status != SUCCESS) {
  518.         NetLERestart(statePtr);
  519.     }
  520.     if (statusPtr != (ReturnStatus *) NIL) {
  521.         *statusPtr = status;
  522.     }
  523.     ENABLE_INTR();
  524.     return status;
  525.     }
  526.  
  527.     /*
  528.      * There is a packet being sent so this packet has to be put onto the
  529.      * transmission queue.  Get an element off of the transmission free list.  
  530.      * If none available then drop the packet.
  531.      */
  532.  
  533.     if (List_IsEmpty(statePtr->xmitFreeList)) {
  534.         scatterGatherPtr->done = TRUE;
  535.     ENABLE_INTR();
  536.     return FAILURE;
  537.     }
  538.  
  539.     xmitPtr = 
  540.     (NetXmitElement *)List_First((List_Links *) statePtr->xmitFreeList);
  541.  
  542.     List_Remove((List_Links *) xmitPtr);
  543.  
  544.     /*
  545.      * Initialize the list element.
  546.      */
  547.     xmitPtr->etherHdrPtr = etherHdrPtr;
  548.     xmitPtr->scatterGatherPtr = scatterGatherPtr;
  549.     xmitPtr->scatterGatherLength = scatterGatherLength;
  550.  
  551.     /* 
  552.      * Put onto the transmission queue.
  553.      */
  554.     List_Insert((List_Links *) xmitPtr, LIST_ATREAR(statePtr->xmitList)); 
  555.  
  556.     if (statusPtr != (ReturnStatus *) NIL) {
  557.     *statusPtr = SUCCESS;
  558.     }
  559.     ENABLE_INTR();
  560.     return SUCCESS;
  561. }
  562.  
  563.  
  564. /*
  565.  *----------------------------------------------------------------------
  566.  *
  567.  * NetLEXmitDrop --
  568.  *
  569.  *    Drop the current packet.  Called at the beginning of the
  570.  *    restart sequence, before curScatGathPtr is reset to NIL.
  571.  *
  572.  * Results:
  573.  *    None.
  574.  *
  575.  * Side effects:
  576.  *    Current scatter gather pointer is reset and processes waiting
  577.  *    for synchronous output are notified.
  578.  *
  579.  *----------------------------------------------------------------------
  580.  */
  581. void
  582. NetLEXmitDrop(statePtr)
  583.     NetLEState        *statePtr;     /* State of the interface. */
  584. {
  585.     if (statePtr->curScatGathPtr != (Net_ScatterGather *) NIL) {
  586.     statePtr->curScatGathPtr->done = TRUE;
  587.     if (statePtr->curScatGathPtr->mutexPtr != (Sync_Semaphore *) NIL) {
  588.         NetOutputWakeup(statePtr->curScatGathPtr->mutexPtr);
  589.     }
  590.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  591.     }
  592. }
  593.  
  594.  
  595. /*
  596.  *----------------------------------------------------------------------
  597.  *
  598.  * NetLEXmitRestart --
  599.  *
  600.  *    Restart transmission of packets after a chip reset.
  601.  *
  602.  * Results:
  603.  *    None.
  604.  *
  605.  * Side effects:
  606.  *    Current scatter gather pointer is reset and new packets may be
  607.  *    sent out.
  608.  *
  609.  *----------------------------------------------------------------------
  610.  */
  611. void
  612. NetLEXmitRestart(statePtr)
  613.     NetLEState        *statePtr;     /* State of the interface. */
  614. {
  615.     NetXmitElement    *xmitElementPtr;
  616.     ReturnStatus    status;
  617.  
  618.     /*
  619.      * Start output if there are any packets queued up.
  620.      */
  621.     if (!List_IsEmpty(statePtr->xmitList)) {
  622.     xmitElementPtr = (NetXmitElement *) List_First(statePtr->xmitList);
  623.     status = OutputPacket(xmitElementPtr->etherHdrPtr,
  624.              xmitElementPtr->scatterGatherPtr,
  625.              xmitElementPtr->scatterGatherLength,
  626.              statePtr);
  627.     if (status != SUCCESS) {
  628.         panic("LE ethernet: Can not output first packet on restart.\n");
  629.     }
  630.     List_Move((List_Links *) xmitElementPtr, 
  631.           LIST_ATREAR(statePtr->xmitFreeList));
  632.     } else {
  633.     statePtr->transmitting = FALSE;
  634.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  635.     }
  636. }
  637.